using System;
using System.Collections.Generic;
using System.Text;
using JobShopModel.Model.FactoryLvl;
using JobShopModel.Model.Station;
using JobShopModel.Model.JobLvl;
using JobShopModel.Model;


namespace JobShopModel.Events
{
    public class PerformOperation : StationEvent
    {

        RegularStation operatingStation;

        public PerformOperation(Time stime, StationsName name)
            : base(stime, name)
        {
            this.operatingStation = (RegularStation)Factory.getInstance().Stations[name];
        }

        /// <summary>
        /// Polymorphic method implemented by all events
        /// </summary>
        public override void Process()
        {
            Factory fact = Factory.getInstance();
            Time elapsedTime = new Time();
            
            //If one machine is availlable
            if (operatingStation.State == StationsStates.AVAILABLE)
            {
                //Get the next job to perform
                if (operatingStation.isJobQueued())
                {
                    Job job = operatingStation.DequeueJob();
                    Operation currentOperation = job.CurrentOperation;

                    //Verification, right Station to do this operation
                    if (currentOperation.Station != StationName)
                    {
                        throw new Exception("Error: Can not perform " + currentOperation + " at " + StationName);
                    }

                    Logger.InsertElement(new LogItem(ItemPriorities.NORMAL, fact.CurrentTime, StationName + ", is doing: " + job.ToString()));

                    /* Perform the operation:
                     *  Get a machine from the station that is iddle
                     *  Set it to Working State
                     *  Get the service time from the operation
                     */

                    //End the Waiting time of the operation
                    currentOperation.setWorking(fact.CurrentTime);

                    //Set the Machine to start the operation and goes to WORKING
                    Machine operatingMachine  = operatingStation.getIddleMachine();
                    Time iddleTime = operatingMachine.SetWorking(fact.CurrentTime + elapsedTime, currentOperation);

                    //Update stats for the station after the first operation:
                    if (fact.CurrentTime.Hours != (Decimal)0 && fact.CurrentTime.Days != 0)
                    {
                        operatingStation.TotalIddleTime = iddleTime;
                        operatingStation.AvgIddleTime = operatingStation.TotalIddleTime / fact.CurrentTime;
                        operatingStation.TotalWaitingQueue += currentOperation.WaitingTime;
                        operatingStation.AvgWaitingQueue = operatingStation.TotalWaitingQueue / operatingStation.JobCounter;
                    }
                    Logger.InsertElement(new LogItem(ItemPriorities.SLOW, fact.CurrentTime, OperatingStation + ", choosing " + operatingMachine.ToString()));
                  
                    
                    //Calculate the future
                    elapsedTime += job.CurrentOperation.ServiceTime;
                    //Raise the end of the operation in the future
                    FinishOperation nextEvent = new FinishOperation(fact.CurrentTime + elapsedTime, StationName, job);
                    fact.EventQueue.insertEvent(nextEvent);
                    Logger.InsertElement(new LogItem(ItemPriorities.CREATION, fact.CurrentTime, StationName + ", has inserted event:" + nextEvent));
                   

                }
                else
                {
                    //TODO how to set a machine back to iddle
                    //operatingStation.State = StationsStates.IDLE;
                    Logger.InsertElement(new LogItem(ItemPriorities.NORMAL, fact.CurrentTime, StationName + ", have no Job left in Queue. Going to IDDLE"));
                }
            }
            else
            {
                Logger.InsertElement(new LogItem(ItemPriorities.NORMAL, fact.CurrentTime, StationName + ", isn't Available all Machines are busy"));
            }


        }

        /// <summary>
        /// Comparison operator (for IComparable)
        /// </summary>
        /// <param name="event1">First event</param>
        /// <param name="event2">Second event</param>
        /// <returns>Returns -1 if event1 occurs first, 1 if event2 occurs first, 0 if the times are the same</returns>
        public override int CompareTo(IEvent event1, IEvent event2)
        {
            if (event1.ExecTime < event2.ExecTime)
                return -1;
            else if (event1.ExecTime > event2.ExecTime)
                return 1;
            else
                return 0;
        }

        public override string ToString()
        {
            return "PerformOperation";
        }
    }
}
